﻿using System;
using System.Linq;
using System.Text;
using DevExpress.Xpo;
using DevExpress.ExpressApp;
using System.ComponentModel;
using DevExpress.ExpressApp.DC;
using DevExpress.Data.Filtering;
using DevExpress.Persistent.Base;
using System.Collections.Generic;
using DevExpress.ExpressApp.Model;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;
using DevExpress.ExpressApp.ConditionalAppearance;
using DevExpress.ExpressApp.Editors;

namespace aztall.Module.BusinessObjects
{
	[DefaultClassOptions, ImageName("BO_Sale"), NavigationItem("Promotions and Sales")]
	[RuleCriteria("", DefaultContexts.Save, "StartDate <= EndDate", CustomMessageTemplate = "Start Date cannot be later than End Date."), XafDisplayName("Promotion")]
	[RuleCombinationOfPropertiesIsUnique("PromoCode Unique", DefaultContexts.Save, "Domain.Oid, PromoCode")]
	public class Promo : DomainObject
	{
		protected string _PromoCode;
		protected string _PromoName;
		protected DateTime _StartDate;
		protected DateTime _EndDate;

		protected DateTime _StoreStartDate;
		protected DateTime _StoreEndDate;
		//[Persistent("PromoCost")]
		protected double? _PromoCost;
		protected XPCollection<AuditDataItemPersistent> changeHistory;
		protected static IList<CustomerSkuDW> DWs = null;

		public Promo(Session session)
				: base(session)
		{
			session.PreFetch<Customer>(Customers);
			session.PreFetch<Sku>(Skus);
			session.PreFetch<PromoCost>(PromoCosts);
			session.PreFetch<PromoVol>(PromoVols);
		}
		public override void AfterConstruction()
		{
			base.AfterConstruction();
		}
		protected override void OnSaving()
		{
			base.OnSaving();
			if (!(base.Session is NestedUnitOfWork))
			{
				UpdatePromoCosts(false);
				//DW.Update(this);
			}
		}
		protected override void OnLoaded()
		{
			Customers.CollectionChanged += Customers_CollectionChanged;
			Skus.CollectionChanged += Skus_CollectionChanged;
			PromoVols.CollectionChanged += PromoVols_CollectionChanged;
			base.OnLoaded();
		}

		private void PromoVols_CollectionChanged(object sender, XPCollectionChangedEventArgs e)
		{
			switch (e.CollectionChangedType)
			{
				case XPCollectionChangedType.AfterAdd:
					UpdatePromoCosts(true);
					break;
				case XPCollectionChangedType.AfterRemove:
					UpdatePromoCosts(true);
					break;
			}
		}
		#region properties
		[ImportColumn(1)]
		[RuleRequiredField(DefaultContexts.Save, SkipNullOrEmptyValues = false)]
		public string PromoCode
		{
			get { return _PromoCode; }
			set { SetPropertyValue(nameof(PromoCode), ref _PromoCode, value); }
		}
		public string PromoName
		{
			get { return _PromoName; }
			set { SetPropertyValue(nameof(PromoName), ref _PromoName, value); }
		}
		public DateTime StartDate
		{
			get { return _StartDate; }
			set
			{
				if (SetPropertyValue(nameof(StartDate), ref _StartDate, value) && !IsLoading)
					UpdatePromoCosts(true);
			}
		}
		public DateTime EndDate
		{
			get { return _EndDate; }
			set
			{
				if (SetPropertyValue(nameof(EndDate), ref _EndDate, value) && !IsLoading)
					UpdatePromoCosts(true);
			}
		}
		public DateTime StoreStartDate
		{
			get { return _StoreStartDate; }
			set
			{
				if (SetPropertyValue(nameof(StoreStartDate), ref _StoreStartDate, value) && !IsLoading)
					UpdatePromoCosts(true);
			}
		}
		public DateTime StoreEndDate
		{
			get { return _StoreEndDate; }
			set
			{
				if (SetPropertyValue(nameof(StoreEndDate), ref _StoreEndDate, value) && !IsLoading)
					UpdatePromoCosts(true);
			}
		}
		public int PromoDays
		{
			get { return (_EndDate - _StartDate).Days + 1; }
		}

		[PersistentAlias("_PromoCost")]
		public double? PromoCost
		{
			get
			{
				//if (!IsLoading && !IsSaving && _PromoCost == null)
				//	UpdatePromoCosts(false);
				return _PromoCost;
			}
			//set
			//{
			//	SetPropertyValue(nameof(PromoCost), ref _PromoCost, value);
			//}
		}


		#endregion
		private void Skus_CollectionChanged(object sender, XPCollectionChangedEventArgs e)
		{
			switch (e.CollectionChangedType)
			{
				case XPCollectionChangedType.AfterAdd:
					UpdatePromoCosts(true);
					break;
				case XPCollectionChangedType.AfterRemove:
					var vols = new XPCollection<PromoVol>(base.Session, new GroupOperator(GroupOperatorType.And, new BinaryOperator("Promo", this), new BinaryOperator("Sku", e.ChangedObject)));
					base.Session.Delete(vols);
					var costs = new XPCollection<PromoCost>(base.Session, new GroupOperator(GroupOperatorType.And, new BinaryOperator("Promo", this), new BinaryOperator("Sku", e.ChangedObject)));
					base.Session.Delete(costs);
					UpdatePromoCosts(true);
					break;
			}
		}

		private void Customers_CollectionChanged(object sender, XPCollectionChangedEventArgs e)
		{
			switch (e.CollectionChangedType)
			{
				case XPCollectionChangedType.AfterAdd:
					UpdatePromoCosts(true);
					break;
				case XPCollectionChangedType.AfterRemove:
					var vols = new XPCollection<PromoVol>(base.Session, new GroupOperator(GroupOperatorType.And, new BinaryOperator("Promo", this), new BinaryOperator("Customer", e.ChangedObject)));
					base.Session.Delete(vols);
					var costs = new XPCollection<PromoCost>(base.Session, new GroupOperator(GroupOperatorType.And, new BinaryOperator("Promo", this), new BinaryOperator("Customer", e.ChangedObject)));
					base.Session.Delete(costs);
					UpdatePromoCosts(true);
					break;
			}
		}
		#region Collections
		[Association("Promo_Customer", UseAssociationNameAsIntermediateTableName = true), DevExpress.Xpo.DisplayName("Customers"), VisibleInDetailView(true)]
		[Index(100), DataSourceCriteria("Domain.Oid = '@This.Domain.Oid'")]
		public XPCollection<Customer> Customers
		{
			get
			{
				return GetCollection<Customer>(nameof(Customers));
			}
		}

		[Association("Promo_Sku", UseAssociationNameAsIntermediateTableName = true), DevExpress.Xpo.DisplayName("Skus"), VisibleInDetailView(true)]
		[Index(200), DataSourceCriteria("Domain.Oid = '@This.Domain.Oid' and Status.StatusCode = 'Active'")]
		public XPCollection<Sku> Skus
		{
			get
			{
				return GetCollection<Sku>(nameof(Skus));
			}
		}

		[Index(300), Association("Promo_PromoCosts", UseAssociationNameAsIntermediateTableName = true), DevExpress.Xpo.Aggregated, DevExpress.Xpo.DisplayName("Promotion Costs"), VisibleInDetailView(true)]
		public XPCollection<PromoCost> PromoCosts
		{
			get
			{
				return GetCollection<PromoCost>(nameof(PromoCosts));
			}
		}
		[Index(400), Association("Promo_PromoVols", UseAssociationNameAsIntermediateTableName = true), DevExpress.Xpo.Aggregated, DevExpress.Xpo.DisplayName("Promotion Volumes"), VisibleInDetailView(true)]
		public XPCollection<PromoVol> PromoVols
		{
			get
			{
				return GetCollection<PromoVol>(nameof(PromoVols));
			}
		}
		[Index(500), DevExpress.Xpo.Aggregated, Association("Promo_PromoAttachments", UseAssociationNameAsIntermediateTableName = true)]
		public XPCollection<PromoAttachment> Attachments
		{
			get { return GetCollection<PromoAttachment>(nameof(Attachments)); }
		}
		[Index(600), DevExpress.Xpo.Aggregated]
		public XPCollection<AuditDataItemPersistent> ChangeHistory
		{
			get
			{
				if (changeHistory == null)
				{
					changeHistory = AuditedObjectWeakReference.GetAuditTrail(Session, this);
				}
				return changeHistory;
			}
		}
		#endregion
		#region Helpers
		bool _SuspendCost = false;
		[NonPersistent, VisibleInDetailView(false), VisibleInListView(false), Browsable(false)]
		public bool SuspendCost
		{
			get { return _SuspendCost; }
			set
			{
				_SuspendCost = value;
				if (!_SuspendCost)
					UpdatePromoCosts(true);
			}
		}
		public void UpdatePromoCosts(bool forceChangedEvent, PromoCost sender = null)
		{
			if (_SuspendCost)
				return;

			double? _oldValue = _PromoCost;
			if (sender == null)
			{
				_PromoCost = 0;
				foreach (PromoCost item in PromoCosts)
				{
					_PromoCost += item.UpdateLineCost(true);
				}
			}
			else
				_PromoCost += sender.UpdateLineCostDelta(true);

			if (forceChangedEvent)
				OnChanged("PromoCost", _oldValue, _PromoCost);
		}

		#endregion

		#region Appearances
		[Appearance("HideStoreDate", Visibility = ViewItemVisibility.Hide, Context = "DetailView", TargetItems = "StoreStartDate;StoreEndDate", AppearanceItemType = "ViewItem")]
		public bool HideStoreDate()
		{
			string c = ConfigValue.FindValue(base.Session, "Hide Promotion Store Dates");
			bool hide = (c == "1");
			return hide;
		}
		[Appearance("HideAttachment", Visibility = ViewItemVisibility.Hide, Context = "DetailView", TargetItems = "Attachments", AppearanceItemType = "LayoutItem")]
		public bool HideAttachment()
		{
			string c = ConfigValue.FindValue(base.Session, "Hide Promotion Attachments");
			bool hide = (c == "1");
			return hide;
		}
		[Appearance("HideChangeHistory", Visibility = ViewItemVisibility.Hide, Context = "DetailView", TargetItems = "ChangeHistory", AppearanceItemType = "LayoutItem")]
		public bool HideChangeHistory()
		{
			string c = ConfigValue.FindValue(base.Session, "Hide Promotion Change History");
			bool hide = (c == "1");
			return hide;
		}
		#endregion
	}
}
